package com.studerb.service;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.log4j.Logger;
import org.hibernate.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.studerb.model.Header;
import com.studerb.model.NewsGroup;
import com.studerb.service.interfaces.IFileService;
import com.studerb.service.interfaces.ISettingsService;
import com.studerb.util.Constants;

public class FileService implements IFileService {
	private final Logger logger = Logger.getLogger(FileService.class);
	private boolean started = false;
	private File baseDir;
	private File articleDir;
	private File downloadDir;
	@Autowired ISettingsService settingsService;
	private AtomicInteger errorCount;

	@Override public File createArticleFile(Header header, byte[] articleBytes) {
		File outputFile = null;
		try {
			NewsGroup newsGroup = header.getNewsGroup();
			File groupDir = createGroupDir(newsGroup);
			String fileName = String.valueOf(header.getArticleNumber()) + "_article" + Constants.ENCODED_FILE_SUFFIX;
			outputFile = new File(groupDir + SystemUtils.FILE_SEPARATOR + fileName);
			FileUtils.writeByteArrayToFile(outputFile, articleBytes);
			logger.debug("wrote encoded ARTICLE bytes to: " + outputFile.getAbsolutePath());
			return outputFile;
		}
		catch (IOException e) {
			e.printStackTrace();
			logger.error("Error creating/opening article file: " + outputFile.getAbsolutePath() + " - " + ExceptionUtils.getRootCause(e));
			incrementError();
			return null;
		}
	}

	private File createGroupDir(NewsGroup newsGroup) {
		String groupDirName = articleDir.getAbsoluteFile() + SystemUtils.FILE_SEPARATOR + newsGroup.getGroupName();
		File groupArticleDir = new File(groupDirName);
		if (!groupArticleDir.exists() && !groupArticleDir.mkdir()) {
			throw new RuntimeException("Error making directory: " + groupArticleDir.getAbsolutePath());
		}
		return groupArticleDir;
	}

	private void incrementError() {
		errorCount.getAndIncrement();
	}

	@Override public boolean isStarted() {
		return started;
	}

	@Override public void start() {
		if (started) {
			throw new RuntimeException("FileService already Started");
		}
		started = true;
		logger.info("[**FileService Starting**]");
		errorCount = new AtomicInteger(0);

		String baseDirString = settingsService.getSetting("fileService.dir");
		String articleDirString = settingsService.getSetting("fileService.articleDir");
		
		//create/assert exists base spool directory
		baseDir = new File(System.getProperty("user.dir") + SystemUtils.FILE_SEPARATOR + baseDirString);
		if (!baseDir.exists() && !baseDir.mkdir()) {
			throw new RuntimeException("Error making directory: " + baseDir.getAbsolutePath());
		}
		articleDir = new File(baseDir.getAbsolutePath() + SystemUtils.FILE_SEPARATOR + articleDirString);
		//create/assert exists article directory
		if (!articleDir.exists() && !articleDir.mkdir()) {
			throw new RuntimeException("Error making directory: " + articleDir.getAbsolutePath());
		}
		try {
			FileUtils.cleanDirectory(articleDir);
		}
		catch (IOException e) {
			logger.warn("Error cleaning: " + articleDir.getAbsolutePath());
			incrementError();
		}
		//create/assert exists DownloadDir
		downloadDir = new File(System.getProperty("user.dir") + SystemUtils.FILE_SEPARATOR +  settingsService.getSetting("fileService.downloadDir"));
		if(!downloadDir.exists() && !downloadDir.mkdir()){
			throw new RuntimeException("Error making directory: " + downloadDir.getAbsolutePath());
		}
		
		
	}

	@Override public void stop() {
		if (!started) {
			throw new RuntimeException("FileService already Stopped");
		}
		logger.info("[**FileService Stopping**]");
		started = false;
	}

	@Override public File createEmptyArticleFile(com.studerb.model.HeaderThread headerThread) {
		File outputFile = null;
		NewsGroup newsGroup = headerThread.getNewsGroup();
		File groupDir = createGroupDir(newsGroup);
		long min = Long.MAX_VALUE;
		long max = Long.MIN_VALUE;
		for(Long article : headerThread.getHeaderArticles()){
			if (article <= min){
				min = article;
			}
			if (article >= max){
				max = article;
			}
		}
		String fileName = String.valueOf(min + "_" + max + "_article" + Constants.ENCODED_FILE_SUFFIX);
		outputFile = new File(groupDir + SystemUtils.FILE_SEPARATOR + fileName);
		logger.debug("created empty ARTICLE File:: " + outputFile.getAbsolutePath());
		return outputFile;
	}

	private File createDownloadDir(NewsGroup newsGroup) {
		File groupDownloadDir = new File(this.downloadDir + SystemUtils.FILE_SEPARATOR + newsGroup.getGroupName());
		if(!groupDownloadDir.exists() && !groupDownloadDir.mkdir()){
			throw new RuntimeException("Error creating news group download dir: " + groupDownloadDir.getAbsolutePath());
		}
		return groupDownloadDir;
	}

	@Override public File getDownloadDirectory(NewsGroup newsGroup) {
		File downloadDir = createDownloadDir(newsGroup);
		return downloadDir;
	}
}
